package com.qen.common;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.qen.conditions.query.LambdaQueryChainWrapper;
import com.qen.conditions.query.QueryChainWrapper;
import com.qen.conditions.update.LambdaUpdateChainWrapper;
import com.qen.conditions.update.UpdateChainWrapper;
import com.qen.wrapper.query.QueryWrapper;
import com.qen.wrapper.update.UpdateWrapper;
import com.qen.interfaces.SFunction;
import com.qen.repository.BaseDao;
import com.qen.wrapper.AbstractWrapper;
import com.qen.wrapper.Wrapper;
import com.qen.wrapper.Wrappers;
import org.beetl.sql.clazz.ClassDesc;
import org.beetl.sql.clazz.TableDesc;
import org.beetl.sql.clazz.kit.BeetlSQLException;
import org.beetl.sql.core.page.PageRequest;
import org.beetl.sql.core.page.PageResult;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 以静态方式调用Service中的函数
 *
 * @author licz
 * @data 2025年05月26日 8:39 AM
 */
public class SqlHelper {

    private SqlHelper() {
        /* Do not new me! */
    }

    /**
     * 返回SelectCount执行结果
     *
     * @param result ignore
     * @return int
     */
    public static long retCount(Long result) {
        return (null == result) ? 0 : result;
    }

    /**
     * 判断数据库操作是否成功
     *
     * @param result 数据库操作返回影响条数
     * @return boolean
     */
    public static boolean retBool(Integer result) {
        return null != result && result >= 1;
    }

    /**
     * 通过entityClass获取BaseDao，再传入lambda使用该dao
     *
     * @param entityClass 实体类
     * @param sFunction   lambda操作，例如 {@code m->m.selectList(wrapper)}
     * @param <T>         实体类的类型
     * @param <R>         返回值类型
     * @param <M>         Mapper类型
     * @return 返回lambda执行结果
     */
    public static <T, R, M extends BaseDao<T>> R execute(Class<T> entityClass, SFunction<M, R> sFunction) {
        M baseDao = BeetlUtils.getDao(entityClass);
        return sFunction.apply(baseDao);
    }

    /**
     * 插入一条记录（选择字段，策略插入）
     *
     * @param entity 实体对象
     */
    public static <T> Object save(T entity) {
        if (Objects.isNull(entity)) {
            return false;
        }
        return execute(getEntityClass(entity), dao -> dao.saveEntity(entity));
    }

    /**
     * 插入（批量）
     *
     * @param entityList 实体对象集合
     */
    public static <T> void saveBatch(List<T> entityList) {
        if (CollectionUtil.isEmpty(entityList)) {
            return;
        }
        Class<T> entityClass = getEntityClass(entityList.get(0));
        execute(entityClass, dao -> dao.addBatch(entityList));
    }

    /**
     * 批量修改插入
     *
     * @param entityList 实体对象集合
     */
    public static <T> boolean[] saveOrUpdateBatch(List<T> entityList) {
        if (CollectionUtil.isEmpty(entityList)) {
            return new boolean[]{false};
        }
        Class<T> entityClass = getEntityClass(entityList);
        return execute(entityClass, dao -> dao.saveBatch(entityList));
    }

    /**
     * 根据 ID 删除
     *
     * @param id          主键ID
     * @param entityClass 实体类
     */
    public static <T> boolean removeById(Serializable id, Class<T> entityClass) {
        return execute(entityClass, dao -> retBool(dao.deleteEntityByKey(id)));
    }

    /**
     * 根据实体(ID)删除
     *
     * @param entity 实体
     */
    public static <T> boolean removeById(T entity) {
        if (Objects.isNull(entity)) {
            return false;
        }
        return execute(getEntityClass(entity), dao -> retBool(dao.deleteEntity(entity)));
    }

    /**
     * 根据 entity 条件，删除记录
     *
     * @param queryWrapper 实体包装类 {@link QueryWrapper}
     */
    public static <T> boolean remove(AbstractWrapper<T, ?, ?> queryWrapper) {
        return execute(getEntityClass(queryWrapper), dao -> retBool(dao.delete(queryWrapper)));
    }

    /**
     * 根据 ID 选择修改
     *
     * @param entity 实体对象
     */
    public static <T> Object updateById(T entity) {
        if (Objects.isNull(entity)) {
            return false;
        }
        return execute(getEntityClass(entity), dao -> dao.updateEntity(entity));
    }

    /**
     * 根据 UpdateWrapper 条件，更新记录 需要设置sqlset
     *
     * @param updateWrapper 实体对象封装操作类 {@link UpdateWrapper}
     */
    public static <T> boolean update(AbstractWrapper<T, ?, ?> updateWrapper) {
        return update(null, updateWrapper);
    }

    /**
     * 根据 whereEntity 条件，更新记录
     *
     * @param entity        实体对象
     * @param updateWrapper 实体对象封装操作类 {@link UpdateWrapper}
     */
    public static <T> boolean update(T entity, AbstractWrapper<T, ?, ?> updateWrapper) {
        return execute(getEntityClass(updateWrapper), dao -> retBool(dao.update(entity, updateWrapper)));
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     * @param batchSize  更新批次数量
     */
    public static <T> int[] updateBatchById(List<T> entityList, int batchSize) {
        Class<T> entityClass = getEntityClass(entityList);
        return execute(entityClass, dao -> dao.updateBatch(entityList));
    }

    /**
     * 删除（根据ID 批量删除）
     *
     * @param list        主键ID或实体列表
     * @param entityClass 实体类
     */
    public static <T> boolean removeByIds(List<? extends Serializable> list, Class<T> entityClass) {
        return execute(entityClass, dao -> retBool(dao.deleteEntityByKey(list)));
    }

    /**
     * 根据 columnMap 条件，删除记录
     *
     * @param columnMap   表字段 map 对象
     * @param entityClass 实体类
     */
    public static <T> boolean removeByMap(Map<String, Object> columnMap, Class<T> entityClass) {
        return execute(entityClass, dao -> retBool(dao.deleteByMap(columnMap)));
    }

    /**
     * TableId 注解存在更新记录，否插入一条记录
     *
     * @param entity 实体对象
     */
    public static <T> Object saveOrUpdate(T entity) {
        if (Objects.isNull(entity)) {
            return false;
        }
        return execute(getEntityClass(entity), dao -> dao.saveEntity(entity));
    }

    /**
     * 根据 ID 查询
     *
     * @param id          主键ID
     * @param entityClass 实体类
     */
    public static <T> T getById(Serializable id, Class<T> entityClass) {
        return execute(entityClass, dao -> dao.findObjectByKey(id));
    }

    /**
     * 根据 Wrapper，查询一条记录 <br/>
     * <p>结果集，如果是多个会抛出异常，随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     */
    public static <T> T getOne(AbstractWrapper<T, ?, ?> queryWrapper) {
        return getOne(queryWrapper, true);
    }

    /**
     * 根据 entity里不为空的字段，查询一条记录 <br/>
     * <p>结果集，如果是多个会抛出异常，随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
     *
     * @param entity 实体对象
     */
    public static <T> T getOne(T entity) {
        return getOne(Wrappers.lambdaQuery(entity), true);
    }

    /**
     * 根据 entity里不为空的字段，查询一条记录
     *
     * @param entity  实体对象
     * @param throwEx 有多个 result 是否抛出异常
     */
    public static <T> T getOne(T entity, boolean throwEx) {
        return getOne(Wrappers.lambdaQuery(entity), throwEx);
    }

    /**
     * 根据 Wrapper，查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @param throwEx      有多个 result 是否抛出异常
     */
    public static <T> T getOne(AbstractWrapper<T, ?, ?> queryWrapper, boolean throwEx) {
        Class<T> entityClass = getEntityClass(queryWrapper);
        if (throwEx) {
            return execute(entityClass, dao -> dao.selectOne(queryWrapper));
        }
        return execute(entityClass, dao -> dao.selectList(queryWrapper).get(0));
    }

    /**
     * 查询（根据 columnMap 条件）
     *
     * @param columnMap   表字段 map 对象
     * @param entityClass 实体类
     */
    public static <T> List<T> listByMap(Map<String, Object> columnMap, Class<T> entityClass) {
        return execute(entityClass, dao -> dao.selectByMap(columnMap));
    }

    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList      主键ID列表
     * @param entityClass 实体类
     */
    public static <T> List<T> listByIds(List<? extends Serializable> idList, Class<T> entityClass) {
        return execute(entityClass, dao -> dao.findObjectByKey(idList));
    }

    /**
     * 根据 Wrapper，查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     */
    public static <T> Map<String, Object> getMap(AbstractWrapper<T, ?, ?> queryWrapper) {
        return execute(getEntityClass(queryWrapper), dao -> dao.selectMaps(queryWrapper).get(0));
    }

    /**
     * 根据 entity不为空条件，查询一条记录
     *
     * @param entity 实体对象
     */
    public static <T> Map<String, Object> getMap(T entity) {
        return getMap(Wrappers.lambdaQuery(entity));
    }

    /**
     * 查询总记录数
     *
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T> long count(Class<T> entityClass) {
        return execute(entityClass, dao -> retCount(dao.selectCount(null)));
    }

    /**
     * 根据entity中不为空的数据查询记录数
     *
     * @param entity 实体类
     */
    public static <T> long count(T entity) {
        return count(Wrappers.lambdaQuery(entity));
    }

    /**
     * 根据 Wrapper 条件，查询总记录数
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     */
    public static <T> long count(AbstractWrapper<T, ?, ?> queryWrapper) {
        return execute(getEntityClass(queryWrapper), dao -> retCount(dao.selectCount(queryWrapper)));
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     */
    public static <T> List<T> list(AbstractWrapper<T, ?, ?> queryWrapper) {
        return execute(getEntityClass(queryWrapper), dao -> dao.selectList(queryWrapper));
    }

    /**
     * @param page         分页条件
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @param <T>          entity
     * @return 列表数据
     */
    public static <T> PageResult<T> list(PageRequest<T> page, AbstractWrapper<T, ?, ?> queryWrapper) {
        return execute(getEntityClass(queryWrapper), dao -> dao.selectList(page, queryWrapper));
    }


    /**
     * 查询所有
     *
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T> List<T> list(Class<T> entityClass) {
        return execute(entityClass, dao -> dao.selectList(null));
    }

    /**
     * @param page        分页条件
     * @param entityClass 实体类
     * @param <T>         entity
     * @return 列表数据
     */
    public static <T> PageResult<T> list(PageRequest<T> page, Class<T> entityClass) {
        return execute(entityClass, dao -> dao.selectList(page, null));
    }


    /**
     * 根据entity中不为空的字段进行查询
     *
     * @param entity 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T> List<T> list(T entity) {
        return list(Wrappers.lambdaQuery(entity));
    }

    /**
     * 根据entity中不为空的字段进行查询
     *
     * @param page   分页条件
     * @param entity 实体类
     * @param <T>    entity
     * @return 列表数据
     */
    public static <T> PageResult<T> list(PageRequest<T> page, T entity) {
        return list(page, Wrappers.lambdaQuery(entity));
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     */
    public static <T> List<Map<String, Object>> listMaps(AbstractWrapper<T, ?, ?> queryWrapper) {
        return execute(getEntityClass(queryWrapper), dao -> dao.selectMaps(queryWrapper));
    }

    /**
     * @param page         分页参数
     * @param queryWrapper queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @param <T>          entity
     * @return 列表数据
     */
    public static <T, P extends PageRequest<Map>> List<Map<String, Object>> listMaps(P page, AbstractWrapper<T, ?, ?> queryWrapper) {
        return execute(getEntityClass(queryWrapper), dao -> dao.selectMaps(page, queryWrapper));
    }

    /**
     * 查询所有列表
     *
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T> List<Map<String, Object>> listMaps(Class<T> entityClass) {
        return execute(entityClass, dao -> dao.selectMaps(null));
    }

    /**
     * 分页查询列表
     *
     * @param page        分页条件
     * @param entityClass 实体类
     * @param <T>         entity
     * @return 列表数据
     */
    public static <T, P extends PageRequest<Map>> List<Map<String, Object>> listMaps(P page, Class<T> entityClass) {
        return execute(entityClass, dao -> dao.selectMaps(page, null));
    }


    /**
     * 根据entity不为空的条件查询列表
     *
     * @param entity 实体类
     */
    public static <T> List<Map<String, Object>> listMaps(T entity) {
        return listMaps(Wrappers.lambdaQuery(entity));
    }

    /**
     * 根据entity不为空的条件查询列表
     *
     * @param page   分页条件
     * @param entity entity
     * @param <T>    entity
     * @return 列表数据
     */
    public static <T> List<Map<String, Object>> listMaps(PageRequest<? extends Map<String, Object>> page, T entity) {
        return listMaps(page, Wrappers.lambdaQuery(entity));
    }

    /**
     * 查询全部记录
     *
     * @param entityClass 实体类
     */
    public static <T> List<T> listObjs(Class<T> entityClass) {
        return listObjs(entityClass, i -> i);
    }

    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     */
    public static <E, T> List<E> listObjs(AbstractWrapper<T, ?, ?> queryWrapper, Class<E> clz) {
        return execute(getEntityClass(queryWrapper), dao -> dao.selectObjs(queryWrapper, clz));
    }

    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @param mapper       转换函数
     */
    public static <T, V> List<V> listObjs(AbstractWrapper<T, ?, ?> queryWrapper, SFunction<? super T, V> mapper) {
        return execute(getEntityClass(queryWrapper), dao -> dao.selectList(queryWrapper).stream().map(mapper).collect(Collectors.toList()));
    }

    /**
     * 查询全部记录
     *
     * @param entityClass 实体类
     * @param mapper      转换函数
     */
    public static <T, V> List<V> listObjs(Class<T> entityClass, SFunction<? super T, V> mapper) {
        return execute(entityClass, dao -> dao.selectList(null).stream().map(mapper).collect(Collectors.toList()));
    }

    /**
     * 无条件翻页查询
     *
     * @param page        翻页对象
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T, P extends PageRequest<Map>> PageResult<Map> pageMaps(P page, Class<T> entityClass) {
        return execute(entityClass, dao -> dao.selectMapsPage(page, null));
    }

    /**
     * 翻页查询
     *
     * @param page         翻页对象
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     */
    public static <T, P extends PageRequest<Map>> PageResult<Map> pageMaps(P page, AbstractWrapper<T, ?, ?> queryWrapper) {
        return execute(getEntityClass(queryWrapper), dao -> dao.selectMapsPage(page, queryWrapper));
    }

    /**
     * 无条件翻页查询
     *
     * @param page        翻页对象
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T> PageResult<T> page(PageRequest<T> page, Class<T> entityClass) {
        return execute(entityClass, dao -> dao.selectPage(page, null));
    }

    /**
     * 翻页查询
     *
     * @param page         翻页对象
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     */
    public static <T> PageResult<T> page(PageRequest<T> page, AbstractWrapper<T, ?, ?> queryWrapper) {
        return execute(getEntityClass(queryWrapper), dao -> dao.selectPage(page, queryWrapper));
    }

    /**
     * 链式查询 普通
     *
     * @return QueryWrapper 的包装类
     */
    public static <T> QueryChainWrapper<T> query(Class<T> entityClass) {
        return ChainWrappers.queryChain(entityClass);
    }

    /**
     * 链式查询 lambda 式
     * <p>注意：不支持 Kotlin </p>
     *
     * @return LambdaQueryWrapper 的包装类
     */
    public static <T> LambdaQueryChainWrapper<T> lambdaQuery(Class<T> entityClass) {
        return ChainWrappers.lambdaQueryChain(entityClass);
    }

    /**
     * 链式更改 普通
     *
     * @return UpdateWrapper 的包装类
     */
    public static <T> UpdateChainWrapper<T> update(Class<T> entityClass) {
        return ChainWrappers.updateChain(entityClass);
    }

    /**
     * 链式更改 lambda 式
     * <p>注意：不支持 Kotlin </p>
     *
     * @return LambdaUpdateWrapper 的包装类
     */
    public static <T> LambdaUpdateChainWrapper<T> lambdaUpdate(Class<T> entityClass) {
        return ChainWrappers.lambdaUpdateChain(entityClass);
    }

    /**
     * <p>
     * 根据updateWrapper尝试更新，否继续执行saveOrUpdate(T)方法
     * 此次修改主要是减少了此项业务代码的代码量（存在性验证之后的saveOrUpdate操作）
     * </p>
     *
     * @param entity 实体对象
     */
    public static <T> boolean saveOrUpdate(T entity, AbstractWrapper<T, ?, ?> updateWrapper) {
        return update(entity, updateWrapper) || saveOrUpdate(entity) != null;
    }

    /**
     * 根据 Wrapper，查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @param mapper       转换函数
     */
    public static <T, V> V getObj(AbstractWrapper<T, ?, ?> queryWrapper, SFunction<? super T, V> mapper) {
        return execute(getEntityClass(queryWrapper), dao -> mapper.apply(dao.selectOne(queryWrapper)));
    }

    /**
     * 根据 whereEntity 条件，更新记录 (null字段也会更新 !!!)
     *
     * @param entity  实体对象 (set 条件值,可以为 null)
     * @param wrapper 实体对象封装操作类（可以为 null,里面的 entity 用于生成 where 语句）
     */
    public static <T> int updateJoinAndNull(T entity, Wrapper<T> wrapper) {
        return execute(wrapper.getEntityClass(), dao -> dao.updateJoinAndNull(entity, wrapper));
    }

    /**
     * 连表查询返回记录集合
     *
     * @param wrapper joinWrapper
     * @param clazz   resultType
     */
    public static <DTO, T> List<DTO> selectJoinList(Class<DTO> clazz, Wrapper<T> wrapper) {
        return execute(wrapper.getEntityClass(), dao -> dao.selectJoinList(clazz, wrapper));
    }

    /**
     * 连表查询返回记录集合并分页
     *
     * @param wrapper joinWrapper
     * @param clazz   resultType
     * @param <DTO>   分页返回对象
     */
    public static <DTO, P extends PageRequest<DTO>, T> PageResult<DTO> selectJoinPage(P page, Class<DTO> clazz, Wrapper<T> wrapper) {
        return execute(wrapper.getEntityClass(), dao -> dao.selectJoinPage(page, clazz, wrapper));
    }

    /**
     * 连表查询返回Map集合并分页
     *
     * @param wrapper joinWrapper
     */
    public <P extends PageRequest<Map>, T> PageResult<Map<String, Object>> selectJoinMapsPage(P page, Wrapper<T> wrapper) {
        return execute(wrapper.getEntityClass(), dao -> dao.selectJoinMapsPage(page, wrapper));
    }

    /**
     * 从集合中获取实体类型
     *
     * @param entityList 实体集合
     * @param <T>        实体类型
     * @return 实体类型
     */
    protected static <T> Class<T> getEntityClass(Collection<T> entityList) {
        Class<T> entityClass = null;
        for (T entity : entityList) {
            if (entity != null) {
                entityClass = getEntityClass(entity);
                break;
            }
        }
        Assert.notNull(entityClass, "error: can not get entityClass from entityList");
        return entityClass;
    }

    /**
     * 从wrapper中尝试获取实体类型
     *
     * @param queryWrapper 条件构造器
     * @param <T>          实体类型
     * @return 实体类型
     */
    protected static <T> Class<T> getEntityClass(AbstractWrapper<T, ?, ?> queryWrapper) {
        Class<T> entityClass = queryWrapper.getEntityClass();
        if (entityClass == null) {
            T entity = queryWrapper.getEntity();
            if (entity != null) {
                entityClass = getEntityClass(entity);
            }
        }
        Assert.notNull(entityClass, "error: can not get entityClass from wrapper");
        return entityClass;
    }

    /**
     * 从entity中尝试获取实体类型
     *
     * @param entity 实体
     * @param <T>    实体类型
     * @return 实体类型
     */
    @SuppressWarnings("unchecked")
    protected static <T> Class<T> getEntityClass(T entity) {
        return (Class<T>) entity.getClass();
    }

    /**
     * 获取表信息，获取不到报错提示
     *
     * @param entityClass 实体类
     * @param <T>         实体类型
     * @return 对应表信息
     */
    protected static <T> TableDesc getTableDesc(Class<T> entityClass) {
        return Optional.ofNullable(TableInfoHelper.getTableInfo(entityClass)).orElseThrow(() ->
                new BeetlSQLException(BeetlSQLException.TABLE_NOT_EXIST,
                        String.format("error: can not find TableDesc from Class: \"%s\".", entityClass.getName())));
    }

    /**
     * 获取POJO类信息，获取不到报错提示
     *
     * @param entityClass 实体类
     * @param <T>         实体类型
     * @return 对应表信息
     */
    protected static <T> ClassDesc getClassDesc(Class<T> entityClass) {
        return Optional.ofNullable(BeetlUtils.getSQLManager().getClassDesc(entityClass)).orElseThrow(() ->
                new BeetlSQLException(BeetlSQLException.TABLE_NOT_EXIST,
                        String.format("error: can not find ClassDesc from Class: \"%s\".", entityClass.getName())));
    }
}
